package canraid.agent.implementations;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelUuid;
import canraid.agent.Cagent;
import canraid.agent.Iagent;
import canraid.config.Properties;
import canraid.debug.Level;
import canraid.debug.Logger;

public class BluetoothAgent extends Cagent {
	private static final UUID MY_UUID_SECURE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
	private static final UUID MY_UUID_INSECURE = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
	private static final int NAME=canraid.gen.R.id.buttonBluetooth;
	
	private String deviceAddress=null;
	private BluetoothDevice mmDevice;
	
	private BluetoothAdapter mAdapter = BluetoothAdapter.getDefaultAdapter();
	private BluetoothSocket mmSocket;
    private boolean isSecure=false;
    private InputStream mmInStream = null;
    private OutputStream mmOutStream = null;
    private Handler[] handlers=null;
    
    private BluetoothAgent me=null;
	
	public BluetoothAgent(String deviceAddress, boolean secure) {
		super(1000); //attesa 1sec del Thread tra un polling e l'altro
		
        Logger.setLog(this,Level.ASSERT,"BluetoothAgent().");
		this.deviceAddress = deviceAddress;
        isSecure=secure;
	}
	
	public int getAgentName(){
		Logger.setLog(this,Level.ASSERT,"getAgentName().");
		return NAME;
	}
	
	protected boolean __setup(){
        Logger.setLog(this,Level.ASSERT,"__setup().");
        
		try {
			if (mAdapter.isDiscovering()) {
	        	Logger.setLog((Object)this,Level.INFO,"__setup(). Stop Discovering.");
	        	mAdapter.cancelDiscovery();
	        }
			
			mmDevice=mAdapter.getRemoteDevice(deviceAddress);
			Logger.setLog((Object)this,Level.INFO,"__setup(). getRemoteDevice("+deviceAddress+")");
			boolean ok=false;
			ParcelUuid[] parcelUUID=mmDevice.getUuids();
			int i=0;
			do {
				try{
					UUID uuid=parcelUUID[i].getUuid();
		            if (isSecure) 
		            	mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);
		            else
		            	mmSocket = mmDevice.createInsecureRfcommSocketToServiceRecord(uuid);
		            
		            Logger.setLog((Object)this,Level.INFO,"__setup(). createSocket, secure?"+isSecure);
		
		            mmSocket.connect();
		            
		            ok=true;
				}catch(Exception e){
					Logger.setLog((Object)this,Level.WARNING,"__setup(). NOT CONNECTED... error("+e.getMessage()+") info("+parcelUUID[i].getUuid().toString()+") with("+i+") tentative("+Integer.toString(i+1)+" of "+parcelUUID.length+")");
					ok=false;
					i++;
					if (i>=parcelUUID.length)
						throw e;
				}
			}while (!ok);
			Logger.setLog((Object)this,Level.INFO,"__setup(). CONNECTED!! with("+i+") info("+parcelUUID[i].getUuid().toString()+")");
            
            
	        mmInStream = mmSocket.getInputStream();
	        Logger.setLog((Object)this,Level.INFO,"__setup(). getInputStream");
	        
	        mmOutStream = mmSocket.getOutputStream();
	        Logger.setLog((Object)this,Level.INFO,"__setup(). getOutputStream");
        
	        handlers = getPoolExternalHandlers();
	        
			if (mmOutStream == null || mmInStream==null){
		        Logger.setLog(this,Level.WARNING,"__setup(). Null Streaming: mmOutStream("+mmOutStream+") mmInStream("+mmInStream+")");
		        throw new Exception("Exception is forced by warning!");
			}
		}
        catch (Exception e) {
            Logger.setLog(this,Level.ERROR,"__setup(). Socket failed - Secure("+isSecure+"); error("+e.getMessage()+")");
            try {
            	if (mmSocket!=null)
            		mmSocket.close();
            } 
            catch (IOException e2) {}
            
        	return false;
        }
        
		return true;
	}
	
	protected boolean __loop(){
        Logger.setLog(this,Level.ASSERT,"__loop().");
        
		try {
			byte[] bufferOutput=__getCopyBufferOutput(true);
			byte[] blockInput = new byte[1024];
			byte[] bufferInput = new byte[0];
			int bytesOutput=bufferOutput.length;
            int bytesBlockInput=-1;
            int bytesBufferInput=bufferInput.length;
			
			if (bytesOutput>0){
				mmOutStream.write(bufferOutput);
		        Logger.setLog(this,Level.INFO,"__loop(). Writing on Bluetooth Device --> "+bytesOutput+" bytes");
			}
			
			do{
				bytesBlockInput =mmInStream.available();
				if (bytesBlockInput>0){
					bytesBlockInput =mmInStream.read(blockInput);
		            Logger.setLog(this,Level.INFO,"__loop(). Read "+bytesBlockInput+" bytes");
		            if (bytesBlockInput>0){
			            byte[] newBuffer=new byte[bufferInput.length + bytesBlockInput];
						System.arraycopy(bufferInput, 0, newBuffer, 0, bufferInput.length);
						System.arraycopy(blockInput, 0, newBuffer, bufferInput.length, bytesBlockInput);
						bufferInput=newBuffer;
					}
				}
			}
			while(bytesBlockInput==blockInput.length);
			
			bytesBufferInput=bufferInput.length;
        	for(int h=0; h<handlers.length;h++){
        		handlers[h].obtainMessage(Iagent.FROM_BT, bytesBufferInput, -1, bufferInput).sendToTarget();
		        Logger.setLog(this,Level.INFO,"__loop(). Sending array_byte len("+bytesBufferInput+") to Handler("+handlers[h].toString()+")");
        	}

			
		} 
		catch (IOException e) {
            Logger.setLog(this,Level.ERROR,"__loop(). Running failed; error("+e.getMessage()+")");
            try {
            	if (mmSocket!=null)
            		mmSocket.close();
            } 
            catch (IOException e2) {}
            
			return false;
		}
		return true;
	}

	protected boolean __implementMyHandler(Message msg) {
		Logger.setLog(this,Level.ASSERT,"__implementMyHandler().");
		
		switch (msg.what) {
		case Iagent.FROM_TEXT:
	    	if (msg.arg1>0){
	        	byte[] data= (byte[]) msg.obj;
	        	Logger.setLog(this,Level.INFO,"__implementMyHandler(). FROM_TEXT");
	        	pushInQueue(data);
	    	}
	    	break;
	    default:
	    	return false;
		}
		return true;
	}

	public void close() {
        Logger.setLog(this,Level.ASSERT,"close().");
        stopPolling();
        
        try {
        	if (mmSocket!=null)
        		mmSocket.close();
        } 
        catch (IOException e2) {}
	}
	
	String [][] UUIDs = new String[][] { {"ServiceDiscoveryServerServiceClassID_UUID", "00001000-0000-1000-8000-00805F9B34FB"},
			{"BrowseGroupDescriptorServiceClassID_UUID", "00001001-0000-1000-8000-00805F9B34FB"},
			{"PublicBrowseGroupServiceClass_UUID", "00001002-0000-1000-8000-00805F9B34FB"},
			{"SerialPortServiceClass_UUID", "00001101-0000-1000-8000-00805F9B34FB"},
			{"LANAccessUsingPPPServiceClass_UUID", "00001102-0000-1000-8000-00805F9B34FB"},
			{"DialupNetworkingServiceClass_UUID", "00001103-0000-1000-8000-00805F9B34FB"},
			{"IrMCSyncServiceClass_UUID", "00001104-0000-1000-8000-00805F9B34FB"},
			{"OBEXObjectPushServiceClass_UUID", "00001105-0000-1000-8000-00805F9B34FB"},
			{"OBEXFileTransferServiceClass_UUID", "00001106-0000-1000-8000-00805F9B34FB"},
			{"IrMCSyncCommandServiceClass_UUID", "00001107-0000-1000-8000-00805F9B34FB"},
			{"HeadsetServiceClass_UUID", "00001108-0000-1000-8000-00805F9B34FB"},
			{"CordlessTelephonyServiceClass_UUID", "00001109-0000-1000-8000-00805F9B34FB"},
			{"AudioSourceServiceClass_UUID", "0000110A-0000-1000-8000-00805F9B34FB"},
			{"AudioSinkServiceClass_UUID", "0000110B-0000-1000-8000-00805F9B34FB"},
			{"AVRemoteControlTargetServiceClass_UUID", "0000110C-0000-1000-8000-00805F9B34FB"},
			{"AdvancedAudioDistributionServiceClass_UUID", "0000110D-0000-1000-8000-00805F9B34FB"},
			{"AVRemoteControlServiceClass_UUID", "0000110E-0000-1000-8000-00805F9B34FB"},
			{"VideoConferencingServiceClass_UUID", "0000110F-0000-1000-8000-00805F9B34FB"},
			{"IntercomServiceClass_UUID", "00001110-0000-1000-8000-00805F9B34FB"},
			{"FaxServiceClass_UUID", "00001111-0000-1000-8000-00805F9B34FB"},
			{"HeadsetAudioGatewayServiceClass_UUID", "00001112-0000-1000-8000-00805F9B34FB"},
			{"WAPServiceClass_UUID", "00001113-0000-1000-8000-00805F9B34FB"},
			{"WAPClientServiceClass_UUID", "00001114-0000-1000-8000-00805F9B34FB"},
			{"PANUServiceClass_UUID", "00001115-0000-1000-8000-00805F9B34FB"},
			{"NAPServiceClass_UUID", "00001116-0000-1000-8000-00805F9B34FB"},
			{"GNServiceClass_UUID", "00001117-0000-1000-8000-00805F9B34FB"},
			{"DirectPrintingServiceClass_UUID", "00001118-0000-1000-8000-00805F9B34FB"},
			{"ReferencePrintingServiceClass_UUID", "00001119-0000-1000-8000-00805F9B34FB"},
			{"ImagingServiceClass_UUID", "0000111A-0000-1000-8000-00805F9B34FB"},
			{"ImagingResponderServiceClass_UUID", "0000111B-0000-1000-8000-00805F9B34FB"},
			{"ImagingAutomaticArchiveServiceClass_UUID", "0000111C-0000-1000-8000-00805F9B34FB"},
			{"ImagingReferenceObjectsServiceClass_UUID", "0000111D-0000-1000-8000-00805F9B34FB"},
			{"HandsfreeServiceClass_UUID", "0000111E-0000-1000-8000-00805F9B34FB"},
			{"HandsfreeAudioGatewayServiceClass_UUID", "0000111F-0000-1000-8000-00805F9B34FB"},
			{"DirectPrintingReferenceObjectsServiceClass_UUID", "00001120-0000-1000-8000-00805F9B34FB"},
			{"ReflectedUIServiceClass_UUID", "00001121-0000-1000-8000-00805F9B34FB"},
			{"BasicPringingServiceClass_UUID", "00001122-0000-1000-8000-00805F9B34FB"},
			{"PrintingStatusServiceClass_UUID", "00001123-0000-1000-8000-00805F9B34FB"},
			{"HumanInterfaceDeviceServiceClass_UUID", "00001124-0000-1000-8000-00805F9B34FB"},
			{"HardcopyCableReplacementServiceClass_UUID", "00001125-0000-1000-8000-00805F9B34FB"},
			{"HCRPrintServiceClass_UUID", "00001126-0000-1000-8000-00805F9B34FB"},
			{"HCRScanServiceClass_UUID", "00001127-0000-1000-8000-00805F9B34FB"},
			{"CommonISDNAccessServiceClass_UUID", "00001128-0000-1000-8000-00805F9B34FB"},
			{"VideoConferencingGWServiceClass_UUID", "00001129-0000-1000-8000-00805F9B34FB"},
			{"UDIMTServiceClass_UUID", "0000112A-0000-1000-8000-00805F9B34FB"},
			{"UDITAServiceClass_UUID", "0000112B-0000-1000-8000-00805F9B34FB"},
			{"AudioVideoServiceClass_UUID", "0000112C-0000-1000-8000-00805F9B34FB"},
			{"SIMAccessServiceClass_UUID", "0000112D-0000-1000-8000-00805F9B34FB"},
			{"PnPInformationServiceClass_UUID", "00001200-0000-1000-8000-00805F9B34FB"},
			{"GenericNetworkingServiceClass_UUID", "00001201-0000-1000-8000-00805F9B34FB"},
			{"GenericFileTransferServiceClass_UUID", "00001202-0000-1000-8000-00805F9B34FB"},
			{"GenericAudioServiceClass_UUID", "00001203-0000-1000-8000-00805F9B34FB"},
			{"GenericTelephonyServiceClass_UUID", "00001204-0000-1000-8000-00805F9B34FB"} };

}
